package cn.xshi.oauth.client.timer;

import cn.hutool.core.collection.CollectionUtil;
import cn.xshi.common.util.RestTemplateUtil;
import cn.xshi.oauth.client.constant.Constant;
import cn.xshi.oauth.client.timer.task.PullTokenTask;
import cn.xshi.oauth.client.util.HeartbeatAttributesUtil;
import cn.xshi.oauth.client.util.OauthAttributesUtil;
import cn.xshi.oauth.client.util.TokenAttributesUtil;
import cn.xshi.oauth.client.vo.Transfer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ForkJoinPool;

/**
 * @Desc Pull 权限
 * @Author 邓纯杰
 * @CreateTime 2012-12-12 12:12:12
 */
@Component
@Slf4j
public class TokenPullScheduled implements CommandLineRunner{

    @Resource
    OauthAttributesUtil oauthAttributesUtil;

    @Resource
    TokenAttributesUtil tokenAttributesUtil;

    @Resource
    RestTemplateUtil restTemplateUtil;

    @Resource
    HeartbeatAttributesUtil heartbeatAttributesUtil;

    @Override
    public void run(String... args) throws Exception {
        new Thread(new TokenPullScheduledRunnable()).start();
    }

    /**
     *
     */
    class TokenPullScheduledRunnable implements Runnable{
        public void run(){
            try {
                while (true){
                    try {
                        if(heartbeatAttributesUtil.isConnected()){
                            initForkJoinPool();
                        }else{
                            log.error("无法连接授权中心...");
                        }
                    }catch (Exception e){
                        log.error("拉取Token信息失败，信息：{}",e);
                    }finally {
                        Thread.sleep(1000);//1秒一次心跳连接
                    }
                }
            }catch (Exception e){
                log.error("拉取Token信息失败，信息：{}",e);
            }
        }
    }

    /**
     * 筛选需要PULL的Token信息
     * @return
     */
    public  Map<String,Transfer> filterKeepAliveToken(){
        Map<String,Transfer> attributes = tokenAttributesUtil.getAttributes();
        Map<String,Transfer> dataMap = new ConcurrentHashMap<>();
        if(CollectionUtil.isEmpty(attributes)){
            return null;
        }
        Iterator<Map.Entry<String, Transfer>> entries = attributes.entrySet().iterator();
        while (entries.hasNext()) {
            Map.Entry<String, Transfer> entry = entries.next();
            if(null != entry.getValue() && entry.getValue().getActionType().equals(Constant.OAUTH_CHANGED)){
                if(!entry.getValue().isLock()){//如果锁了则无法处理
                    dataMap.put(entry.getKey(),entry.getValue());
                }
            }
        }
        return dataMap;
    }

    /**
     *
     */
    public void initForkJoinPool(){
        long millis1 = System.currentTimeMillis();
        int size = Runtime.getRuntime().availableProcessors();//获取本系统的有效线程数，设置线程池为有效线程的两倍。
        ForkJoinPool forkJoinPool = new ForkJoinPool(size*2);
        try {
            Map<String,Transfer> tokenMap = filterKeepAliveToken();
            if(CollectionUtil.isEmpty(tokenMap)){
                return;
            }
            PullTokenTask initTask = new PullTokenTask(tokenMap,Constant.PULL_TOKEN_GROUP_NUMBER,restTemplateUtil,oauthAttributesUtil,tokenAttributesUtil);
            //方法一 同步
            Integer result = forkJoinPool.invoke(initTask);
//                //线程阻塞，等待所有任务完成
//                forkJoinPool.awaitTermination(forkJoinTimeOut, TimeUnit.SECONDS);


//                //方法二 异步
//                ForkJoinTask forkJoinTask = forkJoinPool.submit(initTask);
//                result = new Integer(forkJoinTask.get());


//                //方法三 异步
//                Future<Integer> futureResult = forkJoinPool.submit(initTask);
//                result = futureResult.get();
            long millis2 =  System.currentTimeMillis();
            log.info("更新Token信息:"+(millis2-millis1)+"毫秒，共更新："+result+"条记录！");
        }catch (Exception e){
            if(null != forkJoinPool){
                forkJoinPool.shutdown();
            }
        }finally {
            if(null != forkJoinPool){
                forkJoinPool.shutdown();
            }
        }
    }
}
